{ "cells": [ { "cell_type": "markdown", "id": "4f2ecd13", "metadata": {}, "source": [ "# Populationsdynamik og Bæredygtighed\n", "\n", "Dette materiale er en tilpasset udgave af [Intermat 2.0 modul 3](https://intermat20.compute.dtu.dk/ct/Modul3_elever.html)." ] }, { "cell_type": "markdown", "id": "3064cdce", "metadata": {}, "source": [ "Det er helt centralt i forbindelse med politiske beslutninger for samfundet at kunne forudsige, hvordan en given population udvikler sig fremover. Det er selvsagt vigtigt at se på et lands befolkning og kunne planlægge dagsinstitutioner, skoler, ældrepleje etc., og vurdere den økonomiske bæredygtighed for den demografiske profil. Præcis samme overvejelser er meningsfulde for dyrearter. Det er for eksempel nødvendigt at kunne beskrive dynamikken for en fiskepopulation før man går i gang med at uddele fiskekvoter. Det er samme problemstillinger blot i meget forskellig kontekst.\n", "\n", "I denne notebook vil vi se på modellering af populationer ved brug af matricer og linear algebra. De grundlæggende ideer går tilbage til Patrick Leslie i 1945, som forelog at studere populationer ved at inddele i aldersklasser og trække på viden om klassernes individuelle fertilitets- og overlevelsesrater. Som eksempel så han på den brune rotte. Samlet giver det et diskret, dynamisk system, som kan analyseres med egenværdier og -vektorer.\n", "\n", "Nedenfor vil starte med små og simple modeller med udgangspunkt i kaninpopulationer og Fibonacci-tallene. Modellerne udvides, fertilitetsrater og overlevelsesrater introduceres. Endeligt når vi til en model for den danske befolknings udvikling med betingelser og rater baseret på data fra Danmarks statistik.\n", "\n", "Undervejs vil vi fremhæve væsentlige emner fra lineær algebra, matematisk modellering med Lesliematricer, egenværdier og -vektorer, iteration og konvergens, og vi vil tage nogle små sidespring for at belyse beregningselementer, herunder se på kontrolstrukturer og kompleksitet." ] }, { "cell_type": "markdown", "id": "c7e1fbe3", "metadata": {}, "source": [ "## Program\n", "1. Opvarmning: Fibonacci-tallene genbesøgt\n", "2. Getting real - fødsel og overlevelse\n", "3. Den danske befolkning" ] }, { "cell_type": "markdown", "id": "1eaf610c", "metadata": {}, "source": [ "## Opsætning" ] }, { "cell_type": "code", "execution_count": null, "id": "25cab16c", "metadata": {}, "outputs": [], "source": [ "%matplotlib widget\n", "from gym_cas import *\n", "from spb import graphics, arrow_2d, geometry\n", "from sympy import Circle, Point, re\n", "from ipywidgets import FloatSlider, Layout\n", "from numpy import array\n", "from numpy.linalg import eig" ] }, { "cell_type": "markdown", "id": "35b91f6a", "metadata": {}, "source": [ "# 1. Opvarmning: Fibonacci-tallene genbesøgt\n", "\n", "Fibonacci var en italiensk matematiker i det 13. århundrede; han er også kendt som Leonardo Figlio di Bonacci. Gennem rejser til nord-Afrika stiftede han bekendtskab med det hindu-arabiske talsystem (tallene 0-9, decimaler), som han i sin bog Liber Abaci fra 1203 bragte til Europa. De nye tal afløste romertallene og bragte en revolution for handel og bankvæsenet; også dengang var matematik en kilde til magt og rigdom.\n", "\n", "Fibonacci havde et væsentligt fokus på algoritmer, ligninger og praktisk problem-løsning, og det er helt rimeligt at se ham som en pioner inden for computational thinking. Meget længe inden computerens fødsel. \n", "\n", "I Liber Abaci gennemfører Fibonacci et tankeeksperiment om en kaninpopulations udvikling i isolerede omgivelser. Udgangspunktet er et kaninpar og den matematiske model, at ethvert voksent par giver afkom i form af et nyt, ungt par hver måned. Unger bliver voksne på en måned, og der er ingen dødelighed. \n", "\n", "Vi vælger at tælle hunkaniner fremfor par. Vi starter med én voksen hunkanin, og i en kontekst af en populationsdynamik ser vi på en aldersopdelt populationsmodel, hvor der skelnes mellem to aldersklasser:\n", "\n", "- $\\boldsymbol{x}_k[0]$: antal **unge** hunkaniner efter $k$ måneder,\n", "- $\\boldsymbol{x}_k[1]$: antal **voksne** hunkaniner efter $k$ måneder.\n", "\n", "Til $k=0$ har vi $\\boldsymbol{x}_0[0] = 0$ og $\\boldsymbol{x}_0[1] = 1.$ Dynamikken beskrives ved\n", "\n", "\\begin{align*}\n", " \\boldsymbol{x}_{k+1}[0] &= \\boldsymbol{x}_{k}[1] &\\qquad \\text{(hver voksen kanin giver anledning til en unge i næste måned)},\\\\\n", " \\boldsymbol{x}_{k+1}[1] &= \\boldsymbol{x}_{k}[0] + \\boldsymbol{x}_{k}[1] & \\qquad \\text{(hver unge giver anledning til en voksen i næste måned, og de nuværende voksne overlever)}.\n", "\\end{align*}\n", "\n", "\n", "Hvis vi introducerer matricen\n", "\n", "$$\n", "A = \\begin{bmatrix}0 & 1\\\\[4pt]1 & 1\\end{bmatrix}\n", "$$\n", "så er populationen beskrevet ved det diskrete dynamiske system\n", "\n", "\\begin{align*}\n", "\\boldsymbol{x}_{k+1} = A \\boldsymbol{x}_k, \\quad k = 0,1,2,\\ldots\\;\\;, \\quad \\boldsymbol{x}_0 = \\begin{bmatrix} 0 \\\\ 1 \\end{bmatrix}\n", "\\end{align*}\n", "\n", "Dermed kan vi følge, hvordan antallet af unge og voksne udvikler sig måned for måned.\n", "\n", "Vi kan beskrive udviklingen ved at iterere matricen $A$ så\n", "\n", "$$\n", "\\boldsymbol{x}_1 = A \\boldsymbol{x}_0, \\quad \n", "\\boldsymbol{x}_2 = A \\boldsymbol{x}_1 = A^2 \\boldsymbol{x}_0, \\quad \\dots, \\quad\n", "\\boldsymbol{x}_{k+1} = A \\boldsymbol{x}_k = A^{k+1} \\boldsymbol{x}_0.\n", "$$\n", "\n", "Ser vi kun på det antal af voksne hunkaniner $F_k = \\boldsymbol{x}_k[1]$, genfinder vi rekursionen\n", "\n", "$$\n", "F_{k+1} = F_k + F_{k-1}, \\quad k = 1,2,\\ldots\\;\\;,\n", "$$\n", "\n", "som med begyndelsen $F_0 = F_1 = 1$ lige præcis giver **Fibonacci-tallene** $1,1,2,3,5,8,\\ldots$\n", "\n", "Matricen $A$ kaldes derfor ofte *Fibonacci-matricen*, da hver iteration svarer til én måned i modellen, og den voksen-bestanddel følger Fibonacci-følgen." ] }, { "cell_type": "markdown", "id": "b78c0619", "metadata": {}, "source": [ ">Læg mærke til, hvordan første og anden række i $A$ beskriver henholdsvis næste generations unger og voksne. Fortolk ligeledes søjlerne i $A$ i en kontekst af kaninpopulationer." ] }, { "cell_type": "markdown", "id": "2badd3bd", "metadata": {}, "source": [ "## Iteration og for-løkker i Python\n", "\n", "Løkker (loops) er en såkaldt kontrolstruktur, som tillader os at løbe en gennem en sekvens af elementer og for hvert element udføre en given handling.\n", "\n", "Før vi går i gang med at implementere Fibonacci-matricen og iterere i Python, laver vi en simpel opvarmningsøvelse.\n", "\n", "\n", "\n", "Læs koden nedenfor, og svar på spørgsmålet **inden** du kører den i Python.\n", "\n", "> Hvad forventer du at der bliver printet? Kør koden og sammenlign med din forudsigelse." ] }, { "cell_type": "code", "execution_count": null, "id": "51a25ec9", "metadata": {}, "outputs": [], "source": [ "k = 1\n", "for i in range(5):\n", " k = k + i\n", " print(\"i =\", i, \", k =\", k)" ] }, { "cell_type": "markdown", "id": "c9ca43ec", "metadata": {}, "source": [ "> Hvad sker der hvis vi ændrer `range(5)` til `range(1,6)`?\n", "\n", "> Færdiggør kodecellen nedenfor, så der benyttes et for-loop til at beregne og printe de første $10$ Fibonacci-tal. \\\n", "> NB: I koden bruger vi variablerne `F0` og `F1` til løbende at beregne og overskrive de to seneste Fibonacci-tal. Det kan virke en smule forvirrende, fordi man kunne tro, at `F0` altid repræsenterer det første Fibonacci-tal og `F1` det næste. Her anvender vi dem dog kun som “pladsholdere” for de nyeste værdier i sekvensen - ikke som faste indeks." ] }, { "cell_type": "code", "execution_count": null, "id": "1a3e1689", "metadata": {}, "outputs": [], "source": [ "F0 = \"INDSÆT KODE HER\"\n", "F1 = \"INDSÆT KODE HER\"\n", "\n", "for i in range(\"INDSÆT KODE HER\"):\n", " print(\"INDSÆT KODE HER\")\n", " F0, F1 = \"INDSÆT KODE HER\" , \"INDSÆT KODE HER\"" ] }, { "cell_type": "markdown", "id": "1743c75f", "metadata": {}, "source": [ "## Matrix-iteration" ] }, { "cell_type": "markdown", "id": "fdee0c6f", "metadata": {}, "source": [ "Vi har set, at kaninpopulationen kan beskrives med\n", "\n", "$$\n", "\\boldsymbol{x}_{k+1} = A \\boldsymbol{x}_k = A^{k+1}\\boldsymbol{x}_0, \\quad \n", "A = \\begin{bmatrix}0 & 1\\\\ 1 & 1\\end{bmatrix}.\n", "$$\n", "\n", "hvor startpopulationen er\n", "\n", "$$\n", "\\boldsymbol{x}_0 = \\begin{bmatrix}0\\\\ 1\\end{bmatrix} \\quad \\text{(0 unge, 1 voksen).}\n", "$$" ] }, { "cell_type": "markdown", "id": "86a97b8f", "metadata": {}, "source": [ "> Færdiggør kodecellen nedenfor, så populationen for de første 10 måneder udregnes ved at gentage $\\boldsymbol{x}_{k+1} = A \\boldsymbol{x}_k$. Der printes antal unge, voksne og total for hvert måned. \\\n", "> Du kan bruge `Matrix` til at definere $A$ og `vector` til at definere $x_0$." ] }, { "cell_type": "code", "execution_count": null, "id": "f6c2936f", "metadata": {}, "outputs": [], "source": [ "A = \"INDSÆT KODE HER\"\n", "\n", "startpopulation = \"INDSÆT KODE HER\"\n", "\n", "antal_md = \"INDSÆT KODE HER\"\n", "\n", "print(\"Måned | Unge | Voksne | Total\")\n", "population = startpopulation\n", "for md in range(antal_md):\n", " print(f\"{md:5d} | {int(population[0]):4d} | {int(population[1]):6d} | {int(sum(population)):3d}\")\n", " # Opdater populationen\n", " population = \"INDSÆT KODE HER\"" ] }, { "cell_type": "markdown", "id": "ea10808c", "metadata": {}, "source": [ "I følgende kodecelle ønsker vi at vise udviklingen af voksne kaniner i et plot. Vi bruger listen `voksne_list` til løbende at gemme antallet i hver iteration. \n", "> Færdiggør kodecellen nedenfor, så antallet af voksne kaniner afbildes for de første 10 måneder ved hjælp af matrix-iteration." ] }, { "cell_type": "code", "execution_count": null, "id": "091486e6", "metadata": {}, "outputs": [], "source": [ "A = \"INDSÆT KODE HER\"\n", "\n", "startpopulation = \"INDSÆT KODE HER\"\n", "\n", "antal_md = \"INDSÆT KODE HER\"\n", "\n", "# tome liste til antal voksne kaniner\n", "voksne_list = []\n", "\n", "population = startpopulation.copy()\n", "for md in range(antal_md):\n", " # tilføj antal voksne kaniner til listen\n", " voksne_list.append(population[1])\n", "\n", " # Opdater populationen\n", " population = \"INDSÆT KODE HER\"\n", "\n", "\n", "# Plot antal voksne kaniner\n", "plot_points(\n", " range(antal_md),\n", " voksne_list,\n", " xlabel=\"Måned\",\n", " ylabel=\"Antal voksne kaniner\",\n", " title=\"Udvikling af voksne kaniner (måned 0-9)\",\n", ")" ] }, { "cell_type": "markdown", "id": "d90c5462", "metadata": {}, "source": [ "> Udnyt at $\\boldsymbol{x}_{k} = A^{k}\\boldsymbol{x}_0$ til at finde populationen i måned 9 uden at iterere måned for måned. \\\n", "> $A^{k}$ kan laves med `A**k`." ] }, { "cell_type": "code", "execution_count": null, "id": "80fe8bb2", "metadata": {}, "outputs": [], "source": [ "# INDSÆT KODE HER" ] }, { "cell_type": "markdown", "id": "d3f3d57a", "metadata": {}, "source": [ "> Sammenlign dit resultat med opgaven, hvor du bestemte $\\boldsymbol{x}_{k+1}$ ved at lave gentagne $\\boldsymbol{x}_{k+1}=A\\boldsymbol{x}_k$." ] }, { "cell_type": "markdown", "id": "659ce038", "metadata": {}, "source": [ "## Egenværdier, singulærværdier og asymptotisk udvikling" ] }, { "cell_type": "markdown", "id": "c2575a85", "metadata": {}, "source": [ "En egenværdi $\\lambda \\in \\mathbb{R}$ og tilhørende egenvektor $\\boldsymbol{v} \\neq 0$ opfylder egenværdiproblemet\n", "\n", "$$\n", "A \\boldsymbol{v} = \\lambda \\boldsymbol{v}.\n", "$$\n", "\n", "Det betyder, at når vi anvender matricen $A$ på vektoren $\\boldsymbol{v}$, så bliver resultatet kun en skalering af $\\boldsymbol{v}$ med $\\lambda.$\n", "\n", "Geometrisk er $A v$ parallel med $\\boldsymbol{v}$, men længden ændres med faktor $\\lambda$.\n", "\n", "En egenværdi $\\lambda$ kan findes med determinanten og opfylder ligningen\n", "\n", "$$\n", "\\det(A - \\lambda I) = 0.\n", "$$\n", "\n", "For Fibonacci-matricen $A$ betyder det, at\n", "\n", "$$\n", "\\det\\begin{pmatrix}-\\lambda & 1\\\\ 1 & 1-\\lambda\\end{pmatrix} = -\\lambda(1-\\lambda) - 1 = 0.\n", "$$" ] }, { "cell_type": "markdown", "id": "c8d2a0da", "metadata": {}, "source": [ "> Løs andengradsligningen for $\\lambda$. \n", "\n", "> Indse, at der findes en positiv løsning, $\\lambda = \\lambda_1,$ og en negativ løsning $\\lambda = \\lambda_2,$ og at $\\lambda_1 > |\\lambda_2|.$ Indsæt værdierne i kodecellen nedenfor:" ] }, { "cell_type": "code", "execution_count": null, "id": "0b557019", "metadata": {}, "outputs": [], "source": [ "lambda1 = \"INDSÆT KODE HER\"\n", "lambda2 = \"INDSÆT KODE HER\"" ] }, { "cell_type": "markdown", "id": "cd69927d", "metadata": {}, "source": [ "Vi går nu til en geometrisk fortolkning.\n", "\n", "Nedenfor finder du den interaktive funktion `enhedsvektor_afbildning()`. Det ser omfattende ud, men du behøver ikke forstå hvert trin." ] }, { "cell_type": "code", "execution_count": null, "id": "b56498df", "metadata": {}, "outputs": [], "source": [ "# Definer enhedsvektor som funktion af vinkel t\n", "def xv(t):\n", " return vector(cos(t), sin(t))\n", "\n", "\n", "# Definer billedvektor y = A * x(t)\n", "def yv(A, t):\n", " return A * xv(t)\n", "\n", "\n", "def enhedsvektor_afbildning(A):\n", " \"\"\"\n", " Interaktiv visualisering af enhedsvektorer x og deres billede y = Ax\n", " for en 2x2-matrix A.\n", " \"\"\"\n", "\n", " # Vinkler t fra 0 til 2pi\n", " t_max = int(2 * 3.14 * 100)\n", " ts = [t / t_max for t in range(t_max)]\n", "\n", " # Maksimal værdi for x/y for at skabe passende aksegrænser\n", " max_val = max([max([*abs(xv(tt)), *abs(yv(A, tt))]) for tt in ts])\n", "\n", " params = {\n", " t: FloatSlider(\n", " value=0,\n", " min=0,\n", " max=2 * pi,\n", " step=0.01,\n", " description=\"t\",\n", " layout=Layout(width=\"80%\"),\n", " )\n", " }\n", " circle_plot = geometry(Circle(Point(0, 0), 1), fill=False, show_in_legend=False)\n", " vx_plot = arrow_2d((0, 0), xv(t), \"\\\\vec{x}\", params=params)\n", " vy_plot = arrow_2d((0, 0), yv(A, t), \"A\\\\vec{x}\", params=params)\n", "\n", " return graphics(\n", " circle_plot,\n", " vx_plot,\n", " vy_plot,\n", " aspect=\"equal\",\n", " xlim=(-max_val, max_val),\n", " ylim=(-max_val, max_val),\n", " )" ] }, { "cell_type": "code", "execution_count": null, "id": "897b1d40", "metadata": {}, "outputs": [], "source": [ "# eksempel\n", "A = Matrix([[0., 1],\n", " [1, 1]])\n", "enhedsvektor_afbildning(A)" ] }, { "cell_type": "markdown", "id": "764d9522", "metadata": {}, "source": [ "To vektorer $\\boldsymbol{v}_1$ og $\\boldsymbol{v}_2$ er lineært uafhængige, hvis\n", "\n", "$$\n", "\\alpha \\boldsymbol{v}_1 + \\beta \\boldsymbol{v}_2 = \\boldsymbol{0}\n", "\\ \\Rightarrow\\ \\alpha = 0 \\ \\text{og} \\ \\beta = 0.\n", "$$\n", "\n", "> Aflæs ved brug af `enhedsvektor_afbildning()` to (lineært) uafhængige vektorer $\\boldsymbol{v}=\\boldsymbol{v}_1$ og $\\boldsymbol{v}=\\boldsymbol{v}_2$, for hvilke $A \\boldsymbol{v}$ er parallel med $\\boldsymbol{v}$. Brug evt. funktionen `xv(t)` efter du har fundet en passende værdi for $t$.\n", "\n", "Disse er egenvektorerne. Bemærk, at hvis $\\boldsymbol{v}$ er en egenvektor, så er $c\\boldsymbol{v}$ det også for ethvert tal $c\\in\\mathbb{R}$. Specielt er $-\\boldsymbol{v}$ også en egenvektor med samme egenværdi. \n", "\n", "> Aflæs tilsvarende de tilhørende egenværdier $\\lambda=\\lambda_1$ og $\\lambda=\\lambda_2.$\n", "\n", "> Definer dem i nedenstående kodecelle." ] }, { "cell_type": "code", "execution_count": null, "id": "3afcd55a", "metadata": {}, "outputs": [], "source": [ "v1 = \"INDSÆT VÆRDIER HER\"\n", "lamb1 = \"INDSÆT VÆRDIER HER\"\n", "\n", "v2 = \"INDSÆT VÆRDIER HER\"\n", "lamb2 = \"INDSÆT VÆRDIER HER\"" ] }, { "cell_type": "markdown", "id": "69f8d248", "metadata": {}, "source": [ ">Sammenlign de aflæste egenværdier med de eksakte værdier $\\lambda_1,\\lambda_2$ fundet ovenfor." ] }, { "cell_type": "markdown", "id": "5b8eb07a", "metadata": {}, "source": [ "Egenvektorer hørende til en egenværdi $\\lambda$ kan findes ved at løse ligningen\n", "\n", "$$\n", "(A-\\lambda I )\\boldsymbol{v} = 0.\n", "$$\n", "\n", "I nedenstående kode bruger vi vores indsigt fra SVD til at finde en enhedsvektor $\\boldsymbol{w}_1,$ som (omtrent) er en egenvektor." ] }, { "cell_type": "code", "execution_count": null, "id": "9a6fb6dd", "metadata": {}, "outputs": [], "source": [ "M = A - lambda1 * Matrix.eye(A.shape[0])\n", "\n", "# Beregn SVD af M\n", "U, S, V = M.singular_value_decomposition()\n", "\n", "# Vi husker, at de singulære værdier i S er aftagende, så det sidste må afspejle nulrummet for M\n", "w1 = V[:,1]" ] }, { "cell_type": "markdown", "id": "c682b2ff", "metadata": {}, "source": [ ">Sammenlign den aflæste $\\boldsymbol{v}_1$ med fundne vektor $\\boldsymbol{w}_1$." ] }, { "cell_type": "code", "execution_count": null, "id": "f8ce49d9", "metadata": {}, "outputs": [], "source": [ "display(w1,v1,S)" ] }, { "cell_type": "markdown", "id": "b724202d", "metadata": {}, "source": [ "I Sympy kan egenværdierne og deres tilhørende egenvektorer bestemmes med `A.eigenvects()` eller `eig(A)` fra Numpy." ] }, { "cell_type": "code", "execution_count": null, "id": "5e22c16e", "metadata": {}, "outputs": [], "source": [ "(lamb2, _ , (v2,)), (lamb1, _ , (v1,)) = A.eigenvects()\n", "display(lamb1, lamb2, v1, v2)" ] }, { "cell_type": "markdown", "id": "def79adf", "metadata": {}, "source": [ "> Sammenlign egenværdierne med de teoretiske værdier, som du tidligere har bestemt." ] }, { "cell_type": "markdown", "id": "b2ce4324", "metadata": {}, "source": [ "## Asymptotisk udvikling" ] }, { "cell_type": "markdown", "id": "a11ce10b", "metadata": {}, "source": [ "Vi kan skrive startvektoren som en linearkombination af egenvektorerne $\\boldsymbol{v_1}$ og $\\boldsymbol{v_2}$, så lad\n", "\n", "$$\n", "\\boldsymbol{x}_0 = c_1 \\boldsymbol{v}_1 + c_2 \\boldsymbol{v}_2.\n", "$$\n", "\n", "Når vi anvender matricen $A$ på $\\boldsymbol{x}_0$, får vi pga. linearitet, at\n", "\n", "$$\n", "\\boldsymbol{x}_1 = A \\boldsymbol{x}_0 = A(c_1 \\boldsymbol{v}_1 + c_2 \\boldsymbol{v}_2) = c_1 A \\boldsymbol{v}_1 + c_2 A \\boldsymbol{v}_2 = c_1 \\lambda_1 \\boldsymbol{v}_1 + c_2 \\lambda_2 \\boldsymbol{v}_2.\n", "$$\n", "\n", "Anvendes $A$ igen, fås\n", "\n", "$$\n", "\\boldsymbol{x}_2 = A \\boldsymbol{x}_1 = A(c_1 \\lambda_1 \\boldsymbol{v}_1 + c_2 \\lambda_2 \\boldsymbol{v}_2)\n", "= c_1 \\lambda_1 A \\boldsymbol{v}_1 + c_2 \\lambda_2 A \\boldsymbol{v}_2\n", "= c_1 \\lambda_1^2 \\boldsymbol{v}_1 + c_2 \\lambda_2^2 \\boldsymbol{v}_2.\n", "$$\n", "\n", "Gentager vi processen, får vi for den $k.$ iteration, at\n", "\n", "$$\n", "\\boldsymbol{x}_k = c_1 \\lambda_1^k \\boldsymbol{v}_1 + c_2 \\lambda_2^k \\boldsymbol{v}_2.\n", "$$" ] }, { "cell_type": "markdown", "id": "26c302d1", "metadata": {}, "source": [ "I det følgende ønsker vi at bruge egenvektor-dekompositionen til at beregne $\\boldsymbol{x}_k$ for $k=0,\\dots,K$ via\n", "\n", "$$\n", "\\boldsymbol{x}_k = c_1 \\lambda_1^k \\boldsymbol{v}_1 + c_2 \\lambda_2^k \\boldsymbol{v}_2.\n", "$$\n", "\n", "Først kræver det, at vi bestemmer konstanterne $c_1$ og $c_2$ for $\\boldsymbol{x}_0$. \n", "
\n", "Brug, at vektoren \n", "\n", "$$\n", "\\begin{bmatrix}c_1\\\\c_2\\end{bmatrix}\n", "$$ \n", "\n", "løser ligningssystemet\n", "\n", "$$\n", "\\begin{bmatrix}\\boldsymbol{v}_1&\\boldsymbol{v}_2\\end{bmatrix}\\begin{bmatrix}c_1\\\\c_2\\end{bmatrix}=\\boldsymbol{x}_0\n", "$$\n", "\n", "Vink: Løsningen til et lineært ligningssystem $A\\boldsymbol{x}=\\boldsymbol{b}$ kan bestemmes ved `x=A.solve(b)`." ] }, { "cell_type": "code", "execution_count": null, "id": "22c039e8", "metadata": {}, "outputs": [], "source": [ "startpopulation = vector(0., 1.)\n", "# Saml systemmatrix\n", "V = \"INDSÆT KODE HER\"\n", "\n", "# Løs ligningssystemet\n", "c = \"INDSÆT KODE HER\"\n", "\n", "c1 = \"INDSÆT KODE HER\"\n", "c2 = \"INDSÆT KODE HER\"" ] }, { "cell_type": "markdown", "id": "d2e20427", "metadata": {}, "source": [ "Følgende celle genererer et plot for antal unge og voksne kaniner for $k=0,\\ldots,K$.\n", "\n", ">Færdiggør cellen så $\\boldsymbol{x}_k$ beregnes via egenværdidekompositionen i hver iteration. \\\n", ">*Vink*: Man kan beregne $a^b$ i Python ved `a**b`." ] }, { "cell_type": "code", "execution_count": null, "id": "13f57daf", "metadata": {}, "outputs": [], "source": [ "A = Matrix([[0.0, 1.0], [1.0, 1.0]])\n", "\n", "K = \"INDSÆT KODE HER\" # vælg fx 10 (beregn k=0..K)\n", "\n", "# Beregn x_k vha formel\n", "unge = []\n", "voksne = []\n", "for k in range(K + 1):\n", " xk = \"INDSÆT KODE HER\"\n", " unge.append(xk[0])\n", " voksne.append(xk[1])\n", "\n", "# Plot komponenterne som funktion af k\n", "p1 = plot_points(\n", " range(K + 1),\n", " unge,\n", " label=\"x[0] (unge)\",\n", " show=False,\n", " xlabel=\"Måned (k)\",\n", " ylabel=\"Antal kaniner\",\n", " title=\"Udvikling af hver aldersklasse over tid\",\n", ")\n", "p2 = plot_points(range(K + 1), voksne, label=\"x[1] (voksne)\", show=False)\n", "(p1 + p2).show()" ] }, { "cell_type": "markdown", "id": "8aaa8a39", "metadata": {}, "source": [ "> Tjek at de værdier du får for $\\boldsymbol{x}_k$ er de samme, som dem du tidligere har bestemt." ] }, { "cell_type": "markdown", "id": "ccfcb2d8", "metadata": {}, "source": [ "Hvis vi dividerer begge sider af egenvektor-dekompositionen med $\\lambda_1^k$, fås\n", "\n", "$$\n", "\\frac{\\boldsymbol{x}_k}{\\lambda_1^k} = c_1 \\boldsymbol{v}_1 + c_2 \\left(\\frac{\\lambda_2}{\\lambda_1}\\right)^k \\boldsymbol{v}_2.\n", "$$\n", "\n", "Da $|\\lambda_2 / \\lambda_1| < 1$, vil det andet led gå mod $0$ for $k\\to\\infty$, og dermed fås\n", "\n", "$$\n", "\\frac{\\boldsymbol{x}_k}{\\lambda_1^k} \\to c_1 \\boldsymbol{v}_1 \\quad \\text{for} \\; k\\to \\infty.\n", "$$\n", "\n", "Det betyder, at vektoren $\\boldsymbol{x}_k$ vokser med omtrent $\\lambda_1^k$, og retningen af $\\boldsymbol{x}_k$ nærmer sig $\\boldsymbol{v}_1$. \n", "\n", "
\n", "Vink: Søljevektorer $\\boldsymbol{x}$ og $\\boldsymbol{y}$ kan samles til en matrix $M=\\begin{bmatrix}\\boldsymbol{x}&\\boldsymbol{y}\\end{bmatrix}$ ved `M=x.row_join(y)`.\n", "\n", "
\n", "Hvis vi definerer den demografiske profil som\n", "\n", "$$\n", "\\boldsymbol{d}_k = \\frac{\\boldsymbol{x}_k}{\\|\\boldsymbol{x}_k\\|},\n", "$$\n", "\n", "så vis med papir og blyant, at når $\\boldsymbol{v}_1$ er en enhedsvektor, så er\n", "\n", "$$\n", "\\boldsymbol{d}_k \\to \\boldsymbol{v}_1 \\quad \\text{for } k \\to \\infty.\n", "$$\n", "\n", "\n", "\n", "